home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / streaming / qtspacketizerreassembler / componentvideortp / sources / rtprssmcomponentvideo.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  31.3 KB  |  1,123 lines

  1. /*
  2.     File:        RTPRssmComponentVideo.c
  3.  
  4.     Contains:    Definition of Component Video RTPReassembler
  5.  
  6.     Copyright:    © 1997-1998 by Apple Computer, Inc., all rights reserved.
  7.  
  8.     
  9.     
  10.     OVERVIEW
  11.     
  12.     QuickTime Streaming software uses an RTPReassembler to extract sample data
  13.     from incoming RTP packets.  A base RTPReassembler defined by QuickTime
  14.     Streaming does much of the work of reassembling.  A derived RTPReassembler
  15.     extends the base to interpret a specific RTP payload format, to select an
  16.     appropriate StreamHandler to process reassembled sample data, and to
  17.     handle network packet loss.
  18.     
  19.     This reassembler extends or fully implements the following interface and
  20.     delegates all other calls to its base.
  21.         
  22.         
  23.         STANDARD COMPONENT INTERFACE
  24.         ----------------------------
  25.         
  26.         CallComponentOpen()                Allocate and initialize storage for
  27.                                         instance variables.
  28.         
  29.         CallComponentClose()            Reverse the effects of
  30.                                         CallComponentOpen().
  31.         
  32.         CallComponentVersion()            Return the instance's version.
  33.         
  34.         CallComponentTarget()            Update the instance's inheritance graph.
  35.         
  36.         
  37.         
  38.         RTP REASSEMBLER INTERFACE
  39.         ------------------------------
  40.         
  41.         RTPRssmInitialize()                Prepare to reassemble sample data.
  42.         
  43.         RTPRssmComputeChunkSize()        Determine the size of buffer needed for
  44.                                         the data in a list of network packets.
  45.         
  46.         RTPRssmAdjustPacketParams()        Adjust fields of an RTPRssmPacket to
  47.                                         reflect the properties of its payload.
  48.         
  49.         RTPRssmCopyDataToChunk()        Copy sample data from a packet list to
  50.                                         a data buffer.
  51.         
  52.         RTPRssmSendPacketList()            Prepare to process or discard a list of
  53.                                         packets.
  54.         
  55.         RTPRssmGetInfo()                Return the requested information.
  56.         
  57.         RTPRssmHasCharacteristic()        Indicate whether the reassembler has the
  58.                                         specified characteristic.
  59.         
  60.         RTPRssmReset()                    End processing of the current stream of
  61.                                         network packets.
  62. */
  63.  
  64.  
  65.  
  66. /* ---------------------------------------------------------------------------
  67.  *        H E A D E R S
  68.  * ---------------------------------------------------------------------------
  69.  */
  70.  
  71. #include "RTPRssmComponentVideo.h"
  72. #include "RTPRssmComponentVidResources.h"
  73. #include <FixMath.h>
  74. #include <string.h>
  75.  
  76.  
  77.  
  78. /* ---------------------------------------------------------------------------
  79.  *        R T P    R E A S S E M B L E R    P R O T O T Y P E S
  80.  * ---------------------------------------------------------------------------
  81.  *
  82.  *    QTStreamingComponents.k.h uses these macros to declare prototypes for
  83.  *    the RTPReassembler calls defined in this file.
  84.  *
  85.  */
  86.  
  87. #define RTPRSSM_BASENAME()                RTPRssmComponentVideo_
  88. #define RTPRSSM_GLOBALS()                RTPRssmComponentVideoInstanceData **
  89.  
  90. #include <QTStreamingComponents.k.h>
  91.  
  92.  
  93.  
  94. /* ---------------------------------------------------------------------------
  95.  *        C O M P O N E N T    D I S P A T C H    H E L P E R
  96.  * ---------------------------------------------------------------------------
  97.  *
  98.  *    ComponentDispatchHelper.c uses these macros to define a dispatcher and to
  99.  *    declare prototypes for the core component calls defined in this file.  For
  100.  *    Mac OS, it defines the routine descriptor that serves as the component
  101.  *    entry point.  The name of the routine descriptor is the macro expansion of
  102.  *        
  103.  *        CALLCOMPONENT_BASENAME()##ComponentDispatchRD
  104.  *    
  105.  *    The name of the dispatcher is the macro expansion of
  106.  *    
  107.  *        CALLCOMPONENT_BASENAME()##ComponentDispatch
  108.  *
  109.  */
  110.  
  111. #define CALLCOMPONENT_BASENAME()        RTPRSSM_BASENAME()
  112. #define CALLCOMPONENT_GLOBALS()            RTPRSSM_GLOBALS() storage
  113. #define COMPONENT_DISPATCH_FILE            "RTPRssmComponentVideoDispatch.h"
  114. #define COMPONENT_C_DISPATCHER            1
  115. #define COMPONENT_UPP_SELECT_ROOT()        RTPRssm
  116. #define GET_DELEGATE_COMPONENT()        ( ( **storage ).itsBase )
  117.  
  118. #include <ComponentDispatchHelper.c>
  119.  
  120.  
  121.  
  122. #pragma mark *        INTERNAL IMPLEMENTATION
  123. #pragma mark -
  124. /* ---------------------------------------------------------------------------
  125.  *        I N T E R N A L    I M P L E M E N T A T I O N
  126.  * ---------------------------------------------------------------------------
  127.  */
  128.  
  129. enum
  130. {
  131.     __kDefaultWidth                = 160,
  132.     __kDefaultHeight            = 120,
  133.     __kHorizontalResolution        = 72,
  134.     __kVertivalResolution        = 72,
  135.     __kDepth                    = 24
  136. };
  137.  
  138.  
  139.  
  140. typedef RTPRSSM_GLOBALS()    __InstanceData;
  141.  
  142.  
  143.  
  144. /* ---------------------------------------------------------------------------
  145.  *        __FrameDataSize()
  146.  * ---------------------------------------------------------------------------
  147.  *
  148.  *    Compute the number of octets in one frame of Component Video data having
  149.  *    the given dimensions.
  150.  *    
  151.  *    YUV 4:2:2 encoding uses four octets to represent a pair of pixels.
  152.  *    The number of octets in a frame is therefore
  153.  *    
  154.  *        padded-width x height x 2 octets
  155.  *    
  156.  *    where padded-width is the row width in pixels padded to an
  157.  *    even number.
  158.  *
  159.  */
  160.  
  161. static
  162. UInt32
  163. __FrameDataSize(
  164.     UInt16    inWidth,
  165.     UInt16    inHeight )
  166. {
  167.     return( ( ( ( inWidth + 1 ) & ( ~1L ) ) * inHeight ) << 1 );
  168. }
  169.  
  170.  
  171.  
  172. /* ---------------------------------------------------------------------------
  173.  *        __ReleaseChunk()
  174.  * ---------------------------------------------------------------------------
  175.  *
  176.  *    Release any previously saved chunk.
  177.  *
  178.  */
  179.  
  180. static
  181. SHChunkRecord *
  182. __ReleaseChunk(
  183.     __InstanceData        inGlobals )
  184. {
  185.     SHChunkRecord *        theResult = ( **inGlobals ).itsSavedChunk;
  186.     
  187.     
  188.     if( ( **inGlobals ).itsSavedChunk )
  189.     {
  190.         RTPRssmDecrChunkRefCount(
  191.             ( **inGlobals ).itsFinalDerivation, ( **inGlobals ).itsSavedChunk );
  192.         
  193.         ( **inGlobals ).itsSavedChunk = NULL;
  194.     }
  195.     
  196.     return( theResult );
  197. }
  198.  
  199.  
  200.  
  201. /* ---------------------------------------------------------------------------
  202.  *        __SaveChunk()
  203.  * ---------------------------------------------------------------------------
  204.  *
  205.  *    Release any previously saved chunk and save the given chunk.
  206.  *
  207.  */
  208.  
  209. static
  210. ComponentResult
  211. __SaveChunk(
  212.     __InstanceData        inGlobals,
  213.     SHChunkRecord *        inChunk )
  214. {
  215.     ComponentResult        theResult;
  216.     SHChunkRecord *        thePreviousChunk;
  217.     
  218.     
  219.     thePreviousChunk = __ReleaseChunk( inGlobals );
  220.     
  221.     if( inChunk )
  222.     {
  223.         theResult = RTPRssmIncrChunkRefCount( ( **inGlobals ).itsFinalDerivation, inChunk );
  224.         
  225.         if( theResult == noErr )
  226.             ( **inGlobals ).itsSavedChunk = inChunk;
  227.         else
  228.             theResult = __SaveChunk( inGlobals, thePreviousChunk );
  229.     }
  230.     
  231.     else
  232.     {
  233.         theResult = noErr;
  234.     }
  235.     
  236.     return( theResult );
  237. }
  238.  
  239.  
  240.  
  241. /* ---------------------------------------------------------------------------
  242.  *        __GetNewSampleDescription()
  243.  * ---------------------------------------------------------------------------
  244.  *
  245.  *    Create a new SampleDescription for this reassembler's payload format using
  246.  *    the given dimensions.
  247.  *
  248.  */
  249.  
  250. static
  251. ComponentResult
  252. __GetNewSampleDescription(
  253.     __InstanceData                inGlobals,
  254.     UInt16                        inWidth,
  255.     UInt16                        inHeight,
  256.     SampleDescriptionHandle *    outDescription )
  257. {
  258.     ComponentResult            theResult = noErr;
  259.     ImageDescriptionHandle    theDescription;
  260.     Str255                    theCodecName;
  261.     
  262.     
  263.     theDescription =
  264.         REINTERPRET_CAST( ImageDescriptionHandle )(
  265.             NewHandleClear( sizeof( **theDescription ) ) );
  266.     
  267.     if( theDescription )
  268.     {
  269.         *outDescription = REINTERPRET_CAST( SampleDescriptionHandle )( theDescription );
  270.         
  271.         ( **theDescription ).idSize = sizeof( **theDescription );
  272.         ( **theDescription ).cType = kComponentVideoDataFormat;
  273.         ( **theDescription ).version = 1;
  274.         ( **theDescription ).revisionLevel = 1;
  275.         ( **theDescription ).vendor = kComponentManufactureType;
  276.         ( **theDescription ).temporalQuality = codecNormalQuality;
  277.         ( **theDescription ).spatialQuality = codecNormalQuality;
  278.         ( **theDescription ).width = inWidth;
  279.         ( **theDescription ).height = inHeight;
  280.         ( **theDescription ).hRes = Long2Fix( __kHorizontalResolution );
  281.         ( **theDescription ).vRes = Long2Fix( __kVertivalResolution );
  282.         ( **theDescription ).dataSize = 0;
  283.         ( **theDescription ).frameCount = 1;
  284.         ( **theDescription ).depth = __kDepth;
  285.         ( **theDescription ).clutID = -1;
  286.         
  287.         theCodecName[ 0 ] = '\0';    /* in case string resource doesn't load */
  288.         
  289.         GetComponentIndString(
  290.             REINTERPRET_CAST( Component )( ( **inGlobals ).itself ),
  291.             theCodecName, kRTPRssmComponentVideoStringListResource,
  292.             kRTPRssmComponentVideoCodecNameString );
  293.         
  294.         BlockMoveData(
  295.             theCodecName, ( **theDescription ).name, sizeof( ( **theDescription ).name ) );
  296.     }
  297.     
  298.     else
  299.     {
  300.         *outDescription = 0;
  301.         
  302.         theResult = MemError();
  303.         
  304.         if( theResult == noErr )
  305.             theResult = memFullErr;
  306.     }
  307.     
  308.     return( theResult );
  309. }
  310.  
  311.  
  312.  
  313. /* ---------------------------------------------------------------------------
  314.  *        __GetPayload()
  315.  * ---------------------------------------------------------------------------
  316.  *
  317.  *    Return a pointer to the start of a packet's payload.
  318.  *
  319.  */
  320.  
  321. static
  322. ComponentVideoPayload *
  323. __GetPayload(
  324.     RTPRssmPacket *        inPacket )
  325. {
  326.     return( 
  327.         REINTERPRET_CAST( ComponentVideoPayload * )(
  328.             &inPacket->streamBuffer->rptr[ inPacket->transportHeaderLength ] ) );
  329. }
  330.  
  331.  
  332.  
  333. /* ---------------------------------------------------------------------------
  334.  *        __GetData()
  335.  * ---------------------------------------------------------------------------
  336.  *
  337.  *    Return a pointer to a packet's image data.
  338.  *
  339.  */
  340.  
  341. static
  342. UInt8 *
  343. __GetData(
  344.     RTPRssmPacket *        inPacket )
  345. {
  346.     return( 
  347.         &inPacket->streamBuffer->rptr[
  348.                 inPacket->transportHeaderLength + inPacket->payloadHeaderLength ] );
  349. }
  350.  
  351.  
  352.  
  353. /* ---------------------------------------------------------------------------
  354.  *        __FillMissingData()
  355.  * ---------------------------------------------------------------------------
  356.  *
  357.  *    If the source chunk exists, copy the specified interval from the source
  358.  *    chunk to the target chunk.  Otherwise, set the specified interval of the
  359.  *    target chunk to black.
  360.  *
  361.  */
  362.  
  363. static
  364. void
  365. __FillMissingData(
  366.     UInt32                    inOffset,
  367.     UInt32                    inLength,
  368.     const SHChunkRecord *    inSourceChunk,
  369.     SHChunkRecord *            inTargetChunk )
  370. {
  371.     if( inSourceChunk )
  372.     {
  373.         BlockMoveData(
  374.             &inSourceChunk->dataPtr[ inOffset ],
  375.             CONST_CAST( UInt8 * )( &inTargetChunk->dataPtr[ inOffset ] ),
  376.             inLength );
  377.     }
  378.     
  379.     else
  380.     {
  381.         memset(
  382.             CONST_CAST( UInt8 * )( &inTargetChunk->dataPtr[ inOffset ] ),
  383.             0, inLength );
  384.     }
  385. }
  386.  
  387.  
  388.  
  389. #pragma mark -
  390. #pragma mark *        STANDARD COMPONENT INTERFACE
  391. #pragma mark -
  392. /* ---------------------------------------------------------------------------
  393.  *        S T A N D A R D    C O M P O N E N T    I N T E R F A C E
  394.  * ---------------------------------------------------------------------------
  395.  */
  396.  
  397.  
  398.  
  399. /* ---------------------------------------------------------------------------
  400.  *        + CallComponentOpen() implementation
  401.  * ---------------------------------------------------------------------------
  402.  *
  403.  *    Allocate and initialize storage for instance variables.  When a
  404.  *    reassembler is opened, it is not always called to reassemble data, so this
  405.  *    function doesn't perform any allocations or time-consuming operations that
  406.  *    are needed only to reassemble sample data.  The RTPRssmInitialize()
  407.  *    implementation performs such operations.
  408.  *
  409.  */
  410.  
  411. EXTERN_API( ComponentResult )
  412. RTPRssmComponentVideo_Open(
  413.     __InstanceData        inGlobals,
  414.     ComponentInstance    self )
  415. {
  416.     ComponentResult        theResult = noErr;
  417.     RTPReassembler        theBase;
  418.     
  419.     
  420.     inGlobals =
  421.         REINTERPRET_CAST( __InstanceData )( NewHandleClear( sizeof( **inGlobals ) ) );
  422.     
  423.     if( inGlobals )
  424.     {
  425.         ( **inGlobals ).itself = self;
  426.         ( **inGlobals ).itsFinalDerivation = self;
  427.         
  428.         SetComponentInstanceStorage( self, REINTERPRET_CAST( Handle )( inGlobals ) );
  429.         
  430.         theResult =
  431.             OpenADefaultComponent(
  432.                 kRTPReassemblerType, kRTPBaseReassemblerType, &theBase );
  433.         
  434.         if( theResult == noErr )
  435.         {
  436.             ( **inGlobals ).itsBase = theBase;
  437.             theResult = CallComponentTarget( ( **inGlobals ).itsBase, self );
  438.         }
  439.     }
  440.     
  441.     else
  442.     {
  443.         theResult = MemError();
  444.         
  445.         if( theResult == noErr )
  446.             theResult = memFullErr;
  447.     }
  448.     
  449.     return( theResult );
  450. }
  451.  
  452.  
  453.  
  454. /* ---------------------------------------------------------------------------
  455.  *        + CallComponentClose() implementation
  456.  * ---------------------------------------------------------------------------
  457.  *
  458.  *    Reverse the effects of the CallComponentOpen() implementation.
  459.  *
  460.  */
  461.  
  462. EXTERN_API( ComponentResult )
  463. RTPRssmComponentVideo_Close(
  464.     __InstanceData        inGlobals,
  465.     ComponentInstance    self )
  466. {
  467. #pragma unused( self )
  468.     
  469.     if( inGlobals )
  470.     {
  471.         __ReleaseChunk( inGlobals );
  472.         
  473.         if( ( **inGlobals ).itsBase )
  474.             CloseComponent( ( **inGlobals ).itsBase );
  475.         
  476.         DisposeHandle( REINTERPRET_CAST( Handle )( inGlobals ) );
  477.     }
  478.     
  479.     return( noErr );
  480. }
  481.  
  482.  
  483.  
  484. /* ---------------------------------------------------------------------------
  485.  *        + CallComponentVersion() implementation
  486.  * ---------------------------------------------------------------------------
  487.  *
  488.  *    Return the instance's version.
  489.  *
  490.  */
  491.  
  492. EXTERN_API( ComponentResult )
  493. RTPRssmComponentVideo_Version(
  494.     __InstanceData        inGlobals )
  495. {
  496. #pragma unused( inGlobals )
  497.     
  498.     return( kComponentVersion );
  499. }
  500.  
  501.  
  502.  
  503. /* ---------------------------------------------------------------------------
  504.  *        + CallComponentTarget() implementation
  505.  * ---------------------------------------------------------------------------
  506.  *
  507.  *    Update the instance's inheritance graph with a new most-derived instance.
  508.  *
  509.  */
  510.  
  511. EXTERN_API( ComponentResult )
  512. RTPRssmComponentVideo_Target(
  513.     __InstanceData        inGlobals,
  514.     ComponentInstance    target )
  515. {
  516.     ComponentResult        theResult;
  517.     
  518.     
  519.     if( ( **inGlobals ).itsBase )
  520.         theResult = CallComponentTarget( ( **inGlobals ).itsBase, target );
  521.     else
  522.         theResult = noErr;
  523.     
  524.     if( theResult == noErr )
  525.         ( **inGlobals ).itsFinalDerivation = target;
  526.     
  527.     return( theResult );
  528. }
  529.  
  530.  
  531.  
  532. #pragma mark -
  533. #pragma mark *        RTP REASSEMBLER INTERFACE
  534. #pragma mark -
  535. /* ---------------------------------------------------------------------------
  536.  *        R T P    R E A S S E M B L E R    I N T E R F A C E
  537.  * ---------------------------------------------------------------------------
  538.  */
  539.  
  540.  
  541.  
  542. /* ---------------------------------------------------------------------------
  543.  *        + RTPRssmInitialize() implementation
  544.  * ---------------------------------------------------------------------------
  545.  *
  546.  *    Prepare to reassemble sample data.  This implementation initializes
  547.  *    instance variables that represent the payload state, opens a new
  548.  *    StreamHandler to process reassembled sample data, and sets options that
  549.  *    determine how its base reassembler handles network packets.
  550.  *
  551.  */
  552.  
  553. EXTERN_API( ComponentResult )
  554. RTPRssmComponentVideo_Initialize(
  555.     __InstanceData            inGlobals,
  556.     RTPRssmInitParams *        inInitParams )
  557. {
  558.     ComponentResult                theResult = noErr;
  559.     SampleDescriptionHandle        theDescription;
  560.     
  561.     
  562.     if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPRssmInitializeSelect ) )
  563.         theResult = RTPRssmInitialize( ( **inGlobals ).itsBase, inInitParams );
  564.     
  565.     if( theResult == noErr )
  566.     {
  567.         ( **inGlobals ).itsSavedChunk = NULL;
  568.         
  569.         /*    The reassembler hasn't received a payload description yet, but it can't
  570.             create a new StreamHandler without a SampleDescription.  The reassembler
  571.             initializes its payload attributes with a default description that it
  572.             will use to create a new StreamHandler, then immediately invalidates the
  573.             description.  This causes the reassembler to search incoming network
  574.             packets for a payload description.  If the incoming payload description
  575.             matches the default, the StreamHandler need not be updated. */
  576.         
  577.         ComponentVideoPayloadInitialize(
  578.             &( **inGlobals ).itsPayloadAttributes, __kDefaultWidth, __kDefaultHeight );
  579.         
  580.         ComponentVideoPayloadSetDescription( &( **inGlobals ).itsPayloadAttributes, 0, 0 );
  581.         
  582.         ComponentVideoPayloadSetOffset(
  583.             &( **inGlobals ).itsPayloadAttributes,
  584.             __FrameDataSize( __kDefaultWidth, __kDefaultHeight ) );
  585.         
  586.         theResult =
  587.             __GetNewSampleDescription(
  588.                 inGlobals, __kDefaultWidth, __kDefaultHeight, &theDescription );
  589.         
  590.         if( theResult == noErr )
  591.         {
  592.             theResult =
  593.                 RTPRssmNewStreamHandler(
  594.                     ( **inGlobals ).itsFinalDerivation, VideoMediaType,
  595.                     theDescription, kComponentVideoRTPTimeScale, NULL );
  596.             
  597.             DisposeHandle( REINTERPRET_CAST( Handle )( theDescription ) );
  598.             
  599.             if( theResult == noErr )
  600.             {
  601.                 theResult =
  602.                     RTPRssmSetCapabilities(
  603.                         ( **inGlobals ).itsFinalDerivation,
  604.                         kRTPRssmTrackLostPacketsFlag | kRTPRssmQueueAndUseMarkerBitFlag,
  605.                         -1L );
  606.             }
  607.         }
  608.     }
  609.     
  610.     return( theResult );
  611. }
  612.  
  613.  
  614.  
  615. /* ---------------------------------------------------------------------------
  616.  *        + RTPRssmComputeChunkSize() implementation
  617.  * ---------------------------------------------------------------------------
  618.  *
  619.  *    Use the packet list to determine the size of the data buffer needed to
  620.  *    pass data from these packets to the StreamHandler.  The chunk size for
  621.  *    this reassembler is the image data size for one frame. The size cannot be
  622.  *    computed by summing the data sizes of network packets received, since some
  623.  *    packets might be lost.  Overriding RTPRssmComputeChunkSize() gives the
  624.  *    reassembler a chance to compute the chunk size from the current payload
  625.  *    description.
  626.  *
  627.  *    If the description of the received data is not known, this function
  628.  *    searches the given packet list for a description.  The payload description
  629.  *    is not known if no payload description is cached, or if the description
  630.  *    seed of the incoming network packets doesn't match that of the cached
  631.  *    description.
  632.  *    
  633.  *    (The payload description is also unknown if too many packets have been
  634.  *    lost since the last frame.  Specifically, if the description seeds could
  635.  *    have recycled since the last packet received, then the cached description
  636.  *    is not guaranteed to match the current description, even if it shares the
  637.  *    same seed.  However, since the payload format for this reassembler cycles
  638.  *    through 2^31 seeds, this implementation does not bother to detect this
  639.  *    condition.)
  640.  *    
  641.  *    If a description is found, this function caches the payload description,
  642.  *    updates the StreamHandler's SampleDescription, and updates the Offset
  643.  *    field of the instance's payload attributes with the frame data size
  644.  *    required for that SampleDescription.
  645.  *    
  646.  *    This function always returns the pre-computed data size stored in the
  647.  *    Offset field of the instance's payload attributes instance variable.
  648.  *    Even when the current payload description cannot be determined, the
  649.  *    Offset field gives the chunk size appropriate for the StreamHandler's
  650.  *    current SampleDescription.
  651.  *
  652.  */
  653.  
  654. EXTERN_API( ComponentResult )
  655. RTPRssmComponentVideo_ComputeChunkSize(
  656.     __InstanceData        inGlobals,
  657.     RTPRssmPacket *        inPacketListHead,
  658.     SInt32                 inFlags,
  659.     UInt32 *            outChunkDataSize )
  660. {
  661. #pragma unused( inFlags )
  662.  
  663.     ComponentResult                theResult = noErr;
  664.     RTPRssmPacket *                thePacket;
  665.     ComponentVideoPayload *        thePayload;
  666.     UInt16                        theWidth;
  667.     UInt16                        theHeight;
  668.     SampleDescriptionHandle        theDescription;
  669.     
  670.     
  671.     thePayload = __GetPayload( inPacketListHead );
  672.     
  673.     if(
  674.         ComponentVideoPayloadDescriptionSeed( &( **inGlobals ).itsPayloadAttributes ) !=
  675.             ComponentVideoPayloadDescriptionSeed( thePayload ) )
  676.     {
  677.         ComponentVideoPayloadSetDescription( &( **inGlobals ).itsPayloadAttributes, 0, 0 );
  678.     }
  679.     
  680.     
  681.     /*    If the instance doesn't have a cached payload description, iterate through the
  682.         packet list until it caches an incoming payload description. */
  683.     
  684.     for(
  685.         thePacket = inPacketListHead;
  686.         thePacket  &&
  687.             !ComponentVideoPayloadHasDescription( &( **inGlobals ).itsPayloadAttributes );
  688.         thePacket = thePacket->next )
  689.     {
  690.         thePayload = __GetPayload( thePacket );
  691.         
  692.         if( ComponentVideoPayloadHasDescription( thePayload ) )
  693.         {
  694.             theWidth = ComponentVideoPayloadWidth( thePayload );
  695.             theHeight = ComponentVideoPayloadHeight( thePayload );
  696.             
  697.             
  698.             /*    If the imcoming payload description matches the description last used,
  699.                 simply cache the incoming description.  If they don't match, update
  700.                 the StreamHandler's SampleDescription, update the Offset field of the
  701.                 reassembler's payload attributes, and release any saved chunk as well. */
  702.             
  703.             if(
  704.                 theWidth ==
  705.                     ComponentVideoPayloadWidth( &( **inGlobals ).itsPayloadAttributes )  &&
  706.                 theHeight ==
  707.                     ComponentVideoPayloadHeight( &( **inGlobals ).itsPayloadAttributes ) )
  708.             {
  709.                 ComponentVideoPayloadCopyDescription(
  710.                     &( **inGlobals ).itsPayloadAttributes, thePayload );
  711.             }
  712.             
  713.             else
  714.             {
  715.                 theResult =
  716.                     __GetNewSampleDescription(
  717.                         inGlobals, theWidth, theHeight, &theDescription );
  718.                 
  719.                 if( theResult == noErr )
  720.                 {
  721.                     ComponentVideoPayloadSetOffset(
  722.                         &( **inGlobals ).itsPayloadAttributes,
  723.                         __FrameDataSize( theWidth, theHeight ) );
  724.                     
  725.                     ComponentVideoPayloadCopyDescription(
  726.                         &( **inGlobals ).itsPayloadAttributes, thePayload );
  727.                     
  728.                     __ReleaseChunk( inGlobals );
  729.                     
  730.                     theResult =
  731.                         RTPRssmSetSampleDescription(
  732.                             ( **inGlobals ).itsFinalDerivation, theDescription );
  733.                     
  734.                     DisposeHandle( REINTERPRET_CAST( Handle )( theDescription ) );
  735.                 }
  736.             }
  737.         }
  738.     }
  739.     
  740.     /*    The current data size for incoming frames is always stored in the Offset
  741.         field of the reassembler's payload attributes instance variable. */
  742.     
  743.     *outChunkDataSize =
  744.         ComponentVideoPayloadOffset( &( **inGlobals ).itsPayloadAttributes );
  745.     
  746.     return( theResult );
  747. }
  748.  
  749.  
  750.  
  751. /* ---------------------------------------------------------------------------
  752.  *        + RTPRssmAdjustPacketParams() implementation
  753.  * ---------------------------------------------------------------------------
  754.  *
  755.  *    Adjust fields of the RTPRssmPacket to reflect the properties of its
  756.  *    payload.  The payload format used by this reassembler defines a
  757.  *    variable-length header that immediately precedes the image data.
  758.  *    Overriding RTPRssmAdjustPacketParams() gives the reassembler a chance to
  759.  *    update the RTPRssmPacket data structure for each packet to reflect its
  760.  *    payload header length and image data length.
  761.  *
  762.  */
  763.  
  764. EXTERN_API( ComponentResult )
  765. RTPRssmComponentVideo_AdjustPacketParams(
  766.     __InstanceData        inGlobals,
  767.     RTPRssmPacket *        inPacket,
  768.     SInt32                inFlags )
  769. {
  770. #pragma unused( inGlobals, inFlags )
  771.     
  772.     UInt32                        theHeaderSize;
  773.     ComponentVideoPayload *        thePayload;
  774.     
  775.     
  776.     thePayload = __GetPayload( inPacket );
  777.     
  778.     if( ComponentVideoPayloadHasDescription( thePayload ) )
  779.         theHeaderSize = sizeof( *thePayload );
  780.     else
  781.         theHeaderSize = sizeof( thePayload->itsFixedHeader );
  782.     
  783.     inPacket->payloadHeaderLength = theHeaderSize;
  784.     inPacket->dataLength -= theHeaderSize;
  785.     
  786.     return( noErr );
  787. }
  788.  
  789.  
  790.  
  791. /* ---------------------------------------------------------------------------
  792.  *        + RTPRssmCopyDataToChunk() implementation
  793.  * ---------------------------------------------------------------------------
  794.  *
  795.  *    Copy sample data from a packet list to the data buffer described by an
  796.  *    SHChunkRecord.  The payloads processed by this reassembler indicate where
  797.  *    in the frame the image data from each payload belongs.  This function
  798.  *    iterates through the packets, copying the data to the correct position in
  799.  *    the chunk.  The packet list is ordered by the base reassembler.  Where
  800.  *    packets are missing, this function calls __FillMissingData(), defined
  801.  *    above, to fill in lost packet data with data from the previous frame.
  802.  *
  803.  *    If the payload description has changed without being detected, the image
  804.  *    data might overflow or underflow the buffer.  This function detects these
  805.  *    conditions and invalidates the cached payload description.
  806.  *    
  807.  */
  808.  
  809. EXTERN_API( ComponentResult )
  810. RTPRssmComponentVideo_CopyDataToChunk(
  811.     __InstanceData        inGlobals,
  812.     RTPRssmPacket *        inPacketListHead,
  813.     UInt32                inMaxChunkDataSize,
  814.     SHChunkRecord *        inChunk,
  815.     SInt32                inFlags )
  816. {
  817. #pragma unused( inFlags )
  818.     
  819.     ComponentResult                theResult = noErr;
  820.     RTPRssmPacket *                thePacket;
  821.     ComponentVideoPayload *        thePayload;
  822.     UInt32                        theExpectedOffset;
  823.     UInt32                        theOffset;
  824.     
  825.     
  826.     if(
  827.         inMaxChunkDataSize <
  828.             ComponentVideoPayloadOffset( &( **inGlobals ).itsPayloadAttributes ) )
  829.     {
  830.         /* This should never happen. */
  831.         
  832.         theResult = buffersTooSmall;
  833.     }
  834.     
  835.     
  836.     /* The first packet should contain data for the start of the image buffer. */
  837.     
  838.     theExpectedOffset = 0;
  839.     
  840.     for(
  841.         thePacket = inPacketListHead; thePacket  &&  theResult == noErr;
  842.         thePacket = thePacket->next )
  843.     {
  844.         thePayload = __GetPayload( thePacket );
  845.         theOffset = ComponentVideoPayloadOffset( thePayload );
  846.         
  847.         if( theOffset + thePacket->dataLength <= inMaxChunkDataSize )
  848.         {
  849.             /*    The base reassembler keeps the packets ordered.  If a network packet's
  850.                 data doesn't immediately follow the data from the previous packet in
  851.                 the list, then one or more packets must have been lost. */
  852.             
  853.             if( theExpectedOffset < theOffset )
  854.             {
  855.                 __FillMissingData(
  856.                     theExpectedOffset, theOffset - theExpectedOffset,
  857.                     ( **inGlobals ).itsSavedChunk, inChunk );
  858.             }
  859.             
  860.             BlockMoveData(
  861.                 __GetData( thePacket ),
  862.                 CONST_CAST( UInt8 * )( &inChunk->dataPtr[ theOffset ] ),
  863.                 thePacket->dataLength );
  864.             
  865.             theExpectedOffset = theOffset + thePacket->dataLength;
  866.         }
  867.         
  868.         else
  869.         {
  870.             /*    The image data for the current packet would overflow the image buffer.
  871.                 Therefore the cached payload description is inconsistent with the
  872.                 incoming packet. */
  873.             
  874.             ComponentVideoPayloadSetDescription(
  875.                 &( **inGlobals ).itsPayloadAttributes, 0, 0 );
  876.         }
  877.         
  878.         if( !thePacket->next )
  879.         {
  880.             inChunk->dataSize =
  881.                 ComponentVideoPayloadOffset( &( **inGlobals ).itsPayloadAttributes );
  882.             
  883.             
  884.             /*    If the last packet's data doesnt fill the rest of the image buffer, one
  885.                 or more packets might be missing.  If the RTP/AVP marker bit is set,
  886.                 indicating the last packet of the frame, then the incoming data has
  887.                 underflowed the data buffer, so the cached payload description is
  888.                 inconsistent with the incoming packet. */
  889.             
  890.             if( theExpectedOffset < inChunk->dataSize )
  891.             {
  892.                 __FillMissingData(
  893.                     theExpectedOffset, inChunk->dataSize - theExpectedOffset,
  894.                     ( **inGlobals ).itsSavedChunk, inChunk );
  895.                 
  896.                 if( thePacket->flags & kRTPRssmPacketHasMarkerBitSet )
  897.                 {
  898.                     ComponentVideoPayloadSetDescription(
  899.                         &( **inGlobals ).itsPayloadAttributes, 0, 0 );
  900.                 }
  901.             }
  902.             
  903.             __SaveChunk( inGlobals, inChunk );
  904.         }
  905.     }
  906.     
  907.     return( theResult );
  908. }
  909.  
  910.  
  911.  
  912. /* ---------------------------------------------------------------------------
  913.  *        + RTPRssmSendPacketList() implementation
  914.  * ---------------------------------------------------------------------------
  915.  *
  916.  *    Prepare to process or discard a list of packets.  This reassembler
  917.  *    tolerates packet loss only if it knows the current payload description.
  918.  *    If the base detects that some network packets were lost, overriding
  919.  *    RTPRssmSendPacketList() gives the reassembler a chance to decide whether
  920.  *    it can handle the remaining packets.  This implementation inspects the
  921.  *    packet list to determine whether its payload description is known and
  922.  *    updates the kRTPRssmLostSomePackets flag accordingly.  When the
  923.  *    reassembler is able to recover from packet loss, turning off the
  924.  *    kRTPRssmLostSomePackets flag before delegating the call to the base
  925.  *    reassembler prevents the base from discarding the packets.
  926.  *
  927.  */
  928.  
  929. EXTERN_API( ComponentResult )
  930. RTPRssmComponentVideo_SendPacketList(
  931.     __InstanceData            inGlobals,
  932.     RTPRssmPacket *            inPacketListHead,
  933.     const TimeValue64 *        inLastChunkPresentationTime,
  934.     SInt32                    inFlags )
  935. {
  936.     ComponentVideoPayload *        thePayload;
  937.     RTPRssmPacket *                thePacket;
  938.     
  939.     
  940.     if( inFlags & kRTPRssmLostSomePackets )
  941.     {
  942.         thePayload = __GetPayload( inPacketListHead );
  943.         
  944.         
  945.         /*    If the current payload description is already cached, turn off the packet
  946.             loss flag.  Otherwise, turn off the flag only if the packet list
  947.             contains a payload description. */
  948.         
  949.         if(
  950.             ComponentVideoPayloadHasDescription( &( **inGlobals ).itsPayloadAttributes )  &&
  951.             ComponentVideoPayloadDescriptionSeed( &( **inGlobals ).itsPayloadAttributes ) ==
  952.                 ComponentVideoPayloadDescriptionSeed( thePayload ) )
  953.         {
  954.             inFlags &= ~kRTPRssmLostSomePackets;
  955.         }
  956.         
  957.         else
  958.         {
  959.             for(
  960.                 thePacket = inPacketListHead;
  961.                 thePacket  &&  ( inFlags & kRTPRssmLostSomePackets );
  962.                 thePacket = thePacket->next )
  963.             {
  964.                 thePayload = __GetPayload( thePacket );
  965.                 
  966.                 
  967.                 /*    If a payload description is found, clear the kRTPRssmLostSomePackets
  968.                     flag.  The reassembler will compensate for lost packet data. */
  969.                 
  970.                 if( ComponentVideoPayloadHasDescription( thePayload ) )
  971.                     inFlags &= ~kRTPRssmLostSomePackets;
  972.             }
  973.         }
  974.     }
  975.     
  976.     
  977.     /* Delegate the remaining work to the base reassembler. */
  978.     
  979.     return(
  980.         RTPRssmSendPacketList(
  981.             ( **inGlobals ).itsBase, inPacketListHead, inLastChunkPresentationTime,
  982.             inFlags ) );
  983. }
  984.  
  985.  
  986.  
  987. /* ---------------------------------------------------------------------------
  988.  *        + RTPRssmGetInfo() implementation
  989.  * ---------------------------------------------------------------------------
  990.  *
  991.  *    Return the information indicated by the selector.  This implemenation
  992.  *    computes a result for the following selectors and delegates all others to
  993.  *    its base.
  994.  *
  995.  *
  996.  *        kQTSSourceDimensionsInfo    ioParams points to an QTSDimensionParams
  997.  *                                    structure where the implementation returns
  998.  *                                    the width and height from its cached
  999.  *                                    payload description.
  1000.  *
  1001.  *        kQTSSourceClipRectInfo
  1002.  *        kQTSSourceBoundingRectInfo    ioParams points to a Rect.  The
  1003.  *                                    implementation returns a Rect whose top
  1004.  *                                    left corner is at the origin and whose
  1005.  *                                    width and height are those from its cached
  1006.   *                                    payload description.
  1007. *
  1008.  */
  1009.  
  1010. EXTERN_API( ComponentResult )
  1011. RTPRssmComponentVideo_GetInfo(
  1012.     __InstanceData        inGlobals,
  1013.     OSType                 inSelector,
  1014.     void *                ioParams )
  1015. {
  1016.     ComponentResult            theResult = noErr;
  1017.     QTSDimensionParams *    theDimensions;
  1018.     Rect *                    theRect;
  1019.     
  1020.     
  1021.     switch( inSelector )
  1022.     {
  1023.         case kQTSSourceDimensionsInfo:
  1024.             theDimensions = STATIC_CAST( QTSDimensionParams * )( ioParams );
  1025.             
  1026.             theDimensions->width =
  1027.                 Long2Fix(
  1028.                     ComponentVideoPayloadWidth( &( **inGlobals ).itsPayloadAttributes ) );
  1029.             
  1030.             theDimensions->height =
  1031.                 Long2Fix(
  1032.                     ComponentVideoPayloadHeight( &( **inGlobals ).itsPayloadAttributes ) );
  1033.         break;
  1034.         
  1035.         
  1036.         case kQTSSourceClipRectInfo:
  1037.         case kQTSSourceBoundingRectInfo:
  1038.             theRect = STATIC_CAST( Rect * )( ioParams );
  1039.             
  1040.             MacSetRect(
  1041.                 theRect, 0, 0,
  1042.                 ComponentVideoPayloadWidth( &( **inGlobals ).itsPayloadAttributes ),
  1043.                 ComponentVideoPayloadHeight( &( **inGlobals ).itsPayloadAttributes ) );
  1044.         break;
  1045.         
  1046.         
  1047.         default:
  1048.             theResult =
  1049.                 RTPRssmGetInfo( ( **inGlobals ).itsBase, inSelector, ioParams );
  1050.         break;
  1051.     }
  1052.     
  1053.     return( theResult );
  1054. }
  1055.  
  1056.  
  1057.  
  1058. /* ---------------------------------------------------------------------------
  1059.  *        + RTPRssmHasCharacteristic() implementation
  1060.  * ---------------------------------------------------------------------------
  1061.  *
  1062.  *    Indicate whether the reassembler has the specified characteristic.  This
  1063.  *    reassembler requires ordered packet lists.  All other characteristics are
  1064.  *    delegated to the base.
  1065.  *
  1066.  */
  1067.  
  1068. EXTERN_API( ComponentResult )
  1069. RTPRssmComponentVideo_HasCharacteristic(
  1070.     __InstanceData        inGlobals,
  1071.     OSType                 inCharacteristic,
  1072.     Boolean *            outHasIt )
  1073. {
  1074.     ComponentResult        theResult;
  1075.     
  1076.     
  1077.     if( inCharacteristic == kRTPRssmRequiresOrderedPacketsCharacteristic )
  1078.     {
  1079.         *outHasIt = true;
  1080.         theResult = noErr;
  1081.     }
  1082.  
  1083.     else
  1084.     {
  1085.         theResult =
  1086.             RTPRssmHasCharacteristic( ( **inGlobals ).itsBase, inCharacteristic, outHasIt );
  1087.     }
  1088.     
  1089.     return( theResult );
  1090. }
  1091.  
  1092.  
  1093.  
  1094. /* ---------------------------------------------------------------------------
  1095.  *        + RTPRssmReset() implementation
  1096.  * ---------------------------------------------------------------------------
  1097.  *
  1098.  *    End processing of the current stream of network packets and prepare to
  1099.  *    process a new, possibly unrelated, stream.  This implementation releases
  1100.  *    any saved chunk and invalidates its cached payload description before
  1101.  *    resetting its base.
  1102.  *
  1103.  */
  1104.  
  1105. EXTERN_API( ComponentResult )
  1106. RTPRssmComponentVideo_Reset(
  1107.     __InstanceData        inGlobals,
  1108.     SInt32                inFlags )
  1109. {
  1110.     ComponentResult        theResult;
  1111.     
  1112.     
  1113.     __ReleaseChunk( inGlobals );
  1114.     ComponentVideoPayloadSetDescription( &( **inGlobals ).itsPayloadAttributes, 0, 0 );
  1115.     
  1116.     if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPRssmResetSelect ) )
  1117.         theResult = RTPRssmReset( ( **inGlobals ).itsBase, inFlags );
  1118.     else
  1119.         theResult = noErr;
  1120.     
  1121.     return( theResult );
  1122. }
  1123.